﻿#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

//class person
//{
//public:
//	virtual void BuyTicket()//类成员函数前⾯加virtual修饰，那么这个成员函数被称为虚函数
//	{
//		cout << "买票-全价" << endl;
//	}
//};
////在重写基类虚函数时，派⽣类的虚函数在不加virtual关键字时
//class student : public person {
//public:
//	virtual void BuyTicket()
//	{
//		cout << "买票-打折" << endl;
//	}
//};
//void func(person* ptr)//实现多态的条件1.必须是基类(父类)的指针或引⽤，2.被调⽤的函数必须是虚函数。
//{
//	ptr->BuyTicket();//// 但是跟ptr没关系，⽽是由ptr指向的对象决定的。
//}


//多个子类之间也能实现多态
//class animal
//{
//public:
//	virtual void talk() const
//	{
//
//	}
//};
//class dog :public animal
//{
//public:
//	virtual void talk() const
//	{
//		cout << "汪汪" << endl;
//	}
//};
//class cat : public animal
//{
//public:
//	virtual void talk() const
//	{
//		std::cout << "(>^ω^<)喵" << std::endl;
//	}
//};
//void test(const animal& animal)
//{
//	animal.talk();
//}
//int main()
//{
//	/*person ps;
//	student st;
//	func(&ps);
//	func(&st);*/
//
//	cat c;
//	dog d;
//	test(c);
//	test(d);
//
//	return 0;
//}


//笔试题
//class A
//{
//public:
//	virtual void func(int val = 1) { std::cout << "A->" << val << std::endl; }
//	virtual void test() { func(); }
//};
//class B : public A
//{
//public:
//	void func(int val = 0) { std::cout << "B->" << val << std::endl; }//重写的本质是基类的声明+派生类的实现即
//	                                                                 //virtual void func(int val = 1){ std::cout << "B->" << val << std::endl; }
//};
//int main(int argc, char* argv[])//结果是B->1
//{
//	B* p = new B;
// p->test();//调用父类,test在父类,相当于是隐藏关系,还是指向A  ;多态调用//结果是B->1
// p->func();//结果是B->0
//	return 0;
//}


//析构函数重写
//实际上编译器对析构函数的名称做了特殊处理，编译后析构函数的名称统⼀处理成destructor，
//所以基类的析构函数加了vialtual修饰，派⽣类的析构函数就构成重写。
//class A
//{
//public:
//	virtual ~A()
//	{
//		cout << "~A()" << endl;
//	}
//};
//class B : public A {
//public:
//	~B()
//	{
//		cout << "~B()->delete:" << _p << endl;
//		delete _p;
//	}
//protected:
//	int* _p = new int[10];
//};
//// 只有派⽣类Student的析构函数重写了Person的析构函数，下⾯的delete对象调⽤析构函数，才能
////构成多态，只有构成多态才能保证p1和p2指向的对象正确的调⽤析构函数,否则会造成内存泄漏。
//int main()
//{
//	A* p1 = new A;
//	A* p2 = new B;
//	delete p1;
//	delete p2;
//	return 0;
//}


//C++11提供了override，可以帮助⽤⼾检测是否重写。如果我们不想让派
//⽣类重写这个虚函数，那么可以⽤final去修饰。
//class Car {
//public:
//	virtual void Dirve()
//	{}
//};
//class Benz :public Car {
//public:
//	virtual void Drive() override { cout << "Benz-舒适" << endl; }//Drive和基类的Dirve是不一样的,override可以检测
//};
//int main()
//{
//	return 0;
//}


//如果我们不想让派⽣类重写这个虚函数，那么可以⽤final去修饰。
//class Car
//{
//public:
//	virtual void Drive() final { }
//};
//class Benz :public Car
//{
//public:
//	virtual void Drive() { cout << "Benz-舒适" << endl; }
//};
//int main()
//{
//	return 0;
//}


//纯虚函数和抽象类
//class Car
//{
//	//纯虚函数不需要定义实现(实现没啥意义因为要被
//	//派⽣类重写，但是语法上可以实现)，只要声明即可。包含纯虚函数的类叫做抽象类，抽象类不能实例
//	//化出对象，如果派⽣类继承后不重写纯虚函数，那么派⽣类也是抽象类。
//public:
//	virtual void Drive() = 0;//纯虚函数
//};
//class Benz :public Car
//{
//public:
//	virtual void Drive()
//	{
//		cout << "Benz-舒适" << endl;//重写虚函数可以实例化
//	}
//};
//class BMW :public Car
//{
//public:
//	virtual void Drive()
//	{
//		cout << "BMW-操控" << endl;
//	}
//};
//int main()
//{
//	// 编译报错：error C2259: “Car”: ⽆法实例化抽象类
//	//Car car;//抽象类不能实例化对象
//
//
//	Car* pBenz = new Benz;//父类的指针指向子类
//	pBenz->Drive();
//
//	Car* pBMW = new BMW;
//	pBMW->Drive();
//	return 0;
//}


//多态的原理
//class Person {
//public:
//	virtual void BuyTicket() { cout << "买票-全价" << endl; }
//
//};
//class Student : public Person {
//public:
//	virtual void BuyTicket() { cout << "买票-打折" << endl; }
//};
//class Soldier : public Person {
//public:
//	virtual void BuyTicket() { cout << "买票-优先" << endl; }
//};
//void Func(Person* ptr)
//{
//	// 这⾥可以看到虽然都是Person指针Ptr在调⽤BuyTicket
//	// 但是跟ptr没关系，⽽是由ptr指向的对象决定的。
//	ptr->BuyTicket();//ptr看到的都是person对象,有可能是切片过来的.
//	//指向谁调用谁,指向哪个对象,运行时到指定的虚函数表中找对应虚函数的地址进行调用
//}
//int main()
//{
//	Person ps;
//	Student st;
//	Soldier sr;
//	Func(&ps);
//	Func(&st);
//	Func(&sr);
//	return 0;
//}


//动态绑定与静态绑定
//对不满⾜多态条件(指针或者引⽤+调⽤虚函数)的函数调⽤是在 编译时 绑定，也就是编译时确定调⽤
//函数的地址，叫做静态绑定。
//满⾜多态条件的函数调⽤是在 运⾏时 绑定，也就是在运⾏时到指向对象的虚函数表中找到调⽤函数
//的地址，也就做动态绑定。


//虚函数表
class Base {
public:
	virtual void func1() { cout << "Base::func1" << endl; }//基类对象的虚函数表中存放基类所有虚函数的地址。
	virtual void func2() { cout << "Base::func2" << endl; }
	void func5() { cout << "Base::func5" << endl; }
protected:
	int a = 1;
};
class Derive : public Base
{
public:
	// 重写基类的func1
	virtual void func1() { cout << "Derive::func1" << endl; }
	virtual void func3() { cout << "Derive::func1" << endl; }
	void func4() { cout << "Derive::func4" << endl; }
protected:
	int b = 2;
};
int main()
{
	Base b1;//同类型的对象虚函数表一样,不同对象虚表不一样
	Base b2;

	Derive d;//派⽣类由两部分构成，继承下来的基类和⾃⼰的成员，⼀般情况下，继承下来的基类中有虚函数表
	        //指针，⾃⼰就不会再⽣成虚函数表指针
	return 0;
}
